<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>Symbol | Keith&#39;s blog</title>
    <meta name="generator" content="VuePress 1.8.0">
    <link rel="icon" href="/img/favicon.png">
    <script data-ad-client="ca-pub-7828333725993554" async="async" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
    <meta name="description" content="web前端技术博客,简洁至上,专注web前端学习与总结。JavaScript,js,ES6,TypeScript,vue,python,css3,html5,Node,git,github等技术文章。">
    <meta name="keywords" content="前端博客,个人技术博客,前端,前端开发,前端框架,web前端,前端面试题,技术文档,学习,面试,JavaScript,js,ES6,TypeScript,vue,python,css3,html5,Node,git,github,markdown">
    <meta name="baidu-site-verification" content="7F55weZDDc">
    <meta name="theme-color" content="#11a8cd">
    <link rel="preload" href="/assets/css/0.styles.95a28cfa.css" as="style"><link rel="preload" href="/assets/js/app.ae5bf724.js" as="script"><link rel="preload" href="/assets/js/2.72b09a26.js" as="script"><link rel="preload" href="/assets/js/3.96877024.js" as="script"><link rel="preload" href="/assets/js/95.8042bfa3.js" as="script"><link rel="prefetch" href="/assets/js/10.3e431465.js"><link rel="prefetch" href="/assets/js/100.c7b84f24.js"><link rel="prefetch" href="/assets/js/101.e5a7e6f5.js"><link rel="prefetch" href="/assets/js/102.85992487.js"><link rel="prefetch" href="/assets/js/103.3f187c57.js"><link rel="prefetch" href="/assets/js/104.103d7471.js"><link rel="prefetch" href="/assets/js/105.df0063c0.js"><link rel="prefetch" href="/assets/js/106.d3f285ee.js"><link rel="prefetch" href="/assets/js/107.7ca5e73a.js"><link rel="prefetch" href="/assets/js/108.b5e1495a.js"><link rel="prefetch" href="/assets/js/109.12b39840.js"><link rel="prefetch" href="/assets/js/11.c0c2ac1e.js"><link rel="prefetch" href="/assets/js/110.2996b4eb.js"><link rel="prefetch" href="/assets/js/111.752c7e87.js"><link rel="prefetch" href="/assets/js/112.7c01a356.js"><link rel="prefetch" href="/assets/js/113.240fbeb5.js"><link rel="prefetch" href="/assets/js/114.502fae11.js"><link rel="prefetch" href="/assets/js/115.28ee11f8.js"><link rel="prefetch" href="/assets/js/116.a3f220c8.js"><link rel="prefetch" href="/assets/js/117.293dbd7c.js"><link rel="prefetch" href="/assets/js/118.7fe06c79.js"><link rel="prefetch" href="/assets/js/119.eb539041.js"><link rel="prefetch" href="/assets/js/12.0ea0beb2.js"><link rel="prefetch" href="/assets/js/120.8502bd78.js"><link rel="prefetch" href="/assets/js/121.696d358f.js"><link rel="prefetch" href="/assets/js/122.a629ef96.js"><link rel="prefetch" href="/assets/js/123.bc97cb45.js"><link rel="prefetch" href="/assets/js/124.e9dbc4a1.js"><link rel="prefetch" href="/assets/js/125.3372248a.js"><link rel="prefetch" href="/assets/js/126.58bf8057.js"><link rel="prefetch" href="/assets/js/127.532c80ac.js"><link rel="prefetch" href="/assets/js/128.a8a9dd63.js"><link rel="prefetch" href="/assets/js/129.952e36b7.js"><link rel="prefetch" href="/assets/js/13.81b38e3a.js"><link rel="prefetch" href="/assets/js/130.3f453493.js"><link rel="prefetch" href="/assets/js/131.15bb01bf.js"><link rel="prefetch" href="/assets/js/132.5e501da7.js"><link rel="prefetch" href="/assets/js/133.fbd296a8.js"><link rel="prefetch" href="/assets/js/134.a455c276.js"><link rel="prefetch" href="/assets/js/135.50985645.js"><link rel="prefetch" href="/assets/js/136.dd156bdc.js"><link rel="prefetch" href="/assets/js/137.91d77519.js"><link rel="prefetch" href="/assets/js/138.af96bbc9.js"><link rel="prefetch" href="/assets/js/139.ff60e390.js"><link rel="prefetch" href="/assets/js/14.13ff5f93.js"><link rel="prefetch" href="/assets/js/140.51ef13cd.js"><link rel="prefetch" href="/assets/js/141.2c36f0bb.js"><link rel="prefetch" href="/assets/js/142.745a5a9d.js"><link rel="prefetch" href="/assets/js/143.ef12ce5a.js"><link rel="prefetch" href="/assets/js/144.d53b8a10.js"><link rel="prefetch" href="/assets/js/145.01c80734.js"><link rel="prefetch" href="/assets/js/146.ff1abf8c.js"><link rel="prefetch" href="/assets/js/147.b334a956.js"><link rel="prefetch" href="/assets/js/148.82d1c504.js"><link rel="prefetch" href="/assets/js/149.4872ca41.js"><link rel="prefetch" href="/assets/js/15.ba6da9d5.js"><link rel="prefetch" href="/assets/js/150.eaa1b09e.js"><link rel="prefetch" href="/assets/js/151.b9deeab6.js"><link rel="prefetch" href="/assets/js/152.8914ff06.js"><link rel="prefetch" href="/assets/js/153.1c968910.js"><link rel="prefetch" href="/assets/js/154.ac2ac8e9.js"><link rel="prefetch" href="/assets/js/155.a41ac4d1.js"><link rel="prefetch" href="/assets/js/156.07ec7daa.js"><link rel="prefetch" href="/assets/js/157.d0cfaeb2.js"><link rel="prefetch" href="/assets/js/158.4a3844de.js"><link rel="prefetch" href="/assets/js/159.cd2739bf.js"><link rel="prefetch" href="/assets/js/16.bd936cd0.js"><link rel="prefetch" href="/assets/js/160.8ea34b7b.js"><link rel="prefetch" href="/assets/js/161.4bb2ece8.js"><link rel="prefetch" href="/assets/js/162.a4b2690b.js"><link rel="prefetch" href="/assets/js/163.85acbc57.js"><link rel="prefetch" href="/assets/js/164.acce92e2.js"><link rel="prefetch" href="/assets/js/165.08b51ce6.js"><link rel="prefetch" href="/assets/js/166.7ad057e5.js"><link rel="prefetch" href="/assets/js/167.2d35a768.js"><link rel="prefetch" href="/assets/js/168.b7790709.js"><link rel="prefetch" href="/assets/js/169.11b5000c.js"><link rel="prefetch" href="/assets/js/17.1d7263eb.js"><link rel="prefetch" href="/assets/js/170.d93daf1f.js"><link rel="prefetch" href="/assets/js/171.14a45c02.js"><link rel="prefetch" href="/assets/js/172.c62eb70d.js"><link rel="prefetch" href="/assets/js/173.9dd4cb5e.js"><link rel="prefetch" href="/assets/js/174.deca226f.js"><link rel="prefetch" href="/assets/js/175.eef20df3.js"><link rel="prefetch" href="/assets/js/176.c09f5a25.js"><link rel="prefetch" href="/assets/js/177.99e3a6a8.js"><link rel="prefetch" href="/assets/js/178.22bd595d.js"><link rel="prefetch" href="/assets/js/179.ef63471d.js"><link rel="prefetch" href="/assets/js/18.9412ae71.js"><link rel="prefetch" href="/assets/js/180.306daca4.js"><link rel="prefetch" href="/assets/js/181.9f8eae15.js"><link rel="prefetch" href="/assets/js/182.36cd1ffa.js"><link rel="prefetch" href="/assets/js/183.0195ae23.js"><link rel="prefetch" href="/assets/js/184.61363002.js"><link rel="prefetch" href="/assets/js/185.d01ed7e5.js"><link rel="prefetch" href="/assets/js/186.915e1946.js"><link rel="prefetch" href="/assets/js/187.392993c9.js"><link rel="prefetch" href="/assets/js/188.afcb3c55.js"><link rel="prefetch" href="/assets/js/189.99313768.js"><link rel="prefetch" href="/assets/js/19.17a0f886.js"><link rel="prefetch" href="/assets/js/190.3740a1c8.js"><link rel="prefetch" href="/assets/js/191.a8cebbb8.js"><link rel="prefetch" href="/assets/js/192.a4e4b0eb.js"><link rel="prefetch" href="/assets/js/193.f87069af.js"><link rel="prefetch" href="/assets/js/194.a83aa1ad.js"><link rel="prefetch" href="/assets/js/195.6cccc323.js"><link rel="prefetch" href="/assets/js/196.0ca74fc2.js"><link rel="prefetch" href="/assets/js/197.e57085c4.js"><link rel="prefetch" href="/assets/js/198.9d8c4195.js"><link rel="prefetch" href="/assets/js/199.e34f6d16.js"><link rel="prefetch" href="/assets/js/20.751f715d.js"><link rel="prefetch" href="/assets/js/200.4f0c1baf.js"><link rel="prefetch" href="/assets/js/201.92b5153f.js"><link rel="prefetch" href="/assets/js/202.9f5b1117.js"><link rel="prefetch" href="/assets/js/203.84c5aa3f.js"><link rel="prefetch" href="/assets/js/204.950ec43f.js"><link rel="prefetch" href="/assets/js/205.3caa1fd5.js"><link rel="prefetch" href="/assets/js/206.c5d73eeb.js"><link rel="prefetch" href="/assets/js/207.f00a7726.js"><link rel="prefetch" href="/assets/js/208.49394867.js"><link rel="prefetch" href="/assets/js/209.f891c646.js"><link rel="prefetch" href="/assets/js/21.7e3b1dd6.js"><link rel="prefetch" href="/assets/js/210.9b3ce6fe.js"><link rel="prefetch" href="/assets/js/211.22cbc362.js"><link rel="prefetch" href="/assets/js/212.5380a60a.js"><link rel="prefetch" href="/assets/js/213.64691857.js"><link rel="prefetch" href="/assets/js/214.bf089249.js"><link rel="prefetch" href="/assets/js/215.285eccf0.js"><link rel="prefetch" href="/assets/js/216.e135c2e1.js"><link rel="prefetch" href="/assets/js/217.202ec57b.js"><link rel="prefetch" href="/assets/js/218.c1b5175f.js"><link rel="prefetch" href="/assets/js/219.ac0461eb.js"><link rel="prefetch" href="/assets/js/22.67350c09.js"><link rel="prefetch" href="/assets/js/220.944daf1d.js"><link rel="prefetch" href="/assets/js/221.73cba4fb.js"><link rel="prefetch" href="/assets/js/222.cd29efdd.js"><link rel="prefetch" href="/assets/js/223.5c40831a.js"><link rel="prefetch" href="/assets/js/224.0a05890e.js"><link rel="prefetch" href="/assets/js/225.7c20df0a.js"><link rel="prefetch" href="/assets/js/226.c7f69539.js"><link rel="prefetch" href="/assets/js/227.9ccb8852.js"><link rel="prefetch" href="/assets/js/228.77bd4f2e.js"><link rel="prefetch" href="/assets/js/229.1c656481.js"><link rel="prefetch" href="/assets/js/23.308ebe55.js"><link rel="prefetch" href="/assets/js/230.a3adae2f.js"><link rel="prefetch" href="/assets/js/231.f40d7e85.js"><link rel="prefetch" href="/assets/js/232.762cdd7e.js"><link rel="prefetch" href="/assets/js/233.29242686.js"><link rel="prefetch" href="/assets/js/24.2bb08ee4.js"><link rel="prefetch" href="/assets/js/25.3f1e32c9.js"><link rel="prefetch" href="/assets/js/26.6d06f7bc.js"><link rel="prefetch" href="/assets/js/27.edfd52de.js"><link rel="prefetch" href="/assets/js/28.8c959146.js"><link rel="prefetch" href="/assets/js/29.1621b6ed.js"><link rel="prefetch" href="/assets/js/30.751b1f17.js"><link rel="prefetch" href="/assets/js/31.ec665a74.js"><link rel="prefetch" href="/assets/js/32.1b1d72d5.js"><link rel="prefetch" href="/assets/js/33.b5bd40a4.js"><link rel="prefetch" href="/assets/js/34.2155b0a7.js"><link rel="prefetch" href="/assets/js/35.d59b534a.js"><link rel="prefetch" href="/assets/js/36.44a9c35e.js"><link rel="prefetch" href="/assets/js/37.fd11aa80.js"><link rel="prefetch" href="/assets/js/38.a788fd7b.js"><link rel="prefetch" href="/assets/js/39.0099a8f6.js"><link rel="prefetch" href="/assets/js/4.ff489266.js"><link rel="prefetch" href="/assets/js/40.40c37c27.js"><link rel="prefetch" href="/assets/js/41.a1008003.js"><link rel="prefetch" href="/assets/js/42.5b767b44.js"><link rel="prefetch" href="/assets/js/43.3f71078e.js"><link rel="prefetch" href="/assets/js/44.ad24f6c3.js"><link rel="prefetch" href="/assets/js/45.25e40b16.js"><link rel="prefetch" href="/assets/js/46.b64da983.js"><link rel="prefetch" href="/assets/js/47.17f22f05.js"><link rel="prefetch" href="/assets/js/48.98ac4a14.js"><link rel="prefetch" href="/assets/js/49.2d4cfb58.js"><link rel="prefetch" href="/assets/js/5.90f8b8b3.js"><link rel="prefetch" href="/assets/js/50.961c11a7.js"><link rel="prefetch" href="/assets/js/51.c69cd332.js"><link rel="prefetch" href="/assets/js/52.63e40184.js"><link rel="prefetch" href="/assets/js/53.ed393af3.js"><link rel="prefetch" href="/assets/js/54.e8bf699e.js"><link rel="prefetch" href="/assets/js/55.8c4b1f29.js"><link rel="prefetch" href="/assets/js/56.3ea6fad9.js"><link rel="prefetch" href="/assets/js/57.e355b934.js"><link rel="prefetch" href="/assets/js/58.591ee455.js"><link rel="prefetch" href="/assets/js/59.f75a544d.js"><link rel="prefetch" href="/assets/js/6.01e8382f.js"><link rel="prefetch" href="/assets/js/60.941e9812.js"><link rel="prefetch" href="/assets/js/61.4f56972b.js"><link rel="prefetch" href="/assets/js/62.bd0a67cc.js"><link rel="prefetch" href="/assets/js/63.5525dd5a.js"><link rel="prefetch" href="/assets/js/64.2e40b93d.js"><link rel="prefetch" href="/assets/js/65.7d7a1250.js"><link rel="prefetch" href="/assets/js/66.e88829f6.js"><link rel="prefetch" href="/assets/js/67.233ad823.js"><link rel="prefetch" href="/assets/js/68.037f0252.js"><link rel="prefetch" href="/assets/js/69.d5c49911.js"><link rel="prefetch" href="/assets/js/7.67b2aba3.js"><link rel="prefetch" href="/assets/js/70.039de8ef.js"><link rel="prefetch" href="/assets/js/71.fbbf266f.js"><link rel="prefetch" href="/assets/js/72.2cbdccb2.js"><link rel="prefetch" href="/assets/js/73.f824da30.js"><link rel="prefetch" href="/assets/js/74.c8e2bd49.js"><link rel="prefetch" href="/assets/js/75.2b326b41.js"><link rel="prefetch" href="/assets/js/76.6d52ed9a.js"><link rel="prefetch" href="/assets/js/77.6c219b3f.js"><link rel="prefetch" href="/assets/js/78.e3a6099c.js"><link rel="prefetch" href="/assets/js/79.847c1106.js"><link rel="prefetch" href="/assets/js/8.27cd446a.js"><link rel="prefetch" href="/assets/js/80.8fda2f41.js"><link rel="prefetch" href="/assets/js/81.c64976c1.js"><link rel="prefetch" href="/assets/js/82.44648201.js"><link rel="prefetch" href="/assets/js/83.a02ab71e.js"><link rel="prefetch" href="/assets/js/84.da4c143b.js"><link rel="prefetch" href="/assets/js/85.1e5083cb.js"><link rel="prefetch" href="/assets/js/86.373e4575.js"><link rel="prefetch" href="/assets/js/87.b7dae2d7.js"><link rel="prefetch" href="/assets/js/88.40e11959.js"><link rel="prefetch" href="/assets/js/89.711c7107.js"><link rel="prefetch" href="/assets/js/9.a4f4c6a7.js"><link rel="prefetch" href="/assets/js/90.36268f74.js"><link rel="prefetch" href="/assets/js/91.0b92ab60.js"><link rel="prefetch" href="/assets/js/92.9813b046.js"><link rel="prefetch" href="/assets/js/93.fcd128dd.js"><link rel="prefetch" href="/assets/js/94.c099f487.js"><link rel="prefetch" href="/assets/js/96.45fc745f.js"><link rel="prefetch" href="/assets/js/97.32326e64.js"><link rel="prefetch" href="/assets/js/98.82035585.js"><link rel="prefetch" href="/assets/js/99.b24b3ac3.js">
    <link rel="stylesheet" href="/assets/css/0.styles.95a28cfa.css">
  </head>
  <body class="theme-mode-light">
    <div id="app" data-server-rendered="true"><div class="theme-container sidebar-open have-rightmenu have-body-img"><header class="navbar blur"><div title="目录" class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/" class="home-link router-link-active"><img src="/img/EB-logo.png" alt="Keith's blog" class="logo"> <span class="site-name can-hide">Keith's blog</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/" class="nav-link">首页</a></div><div class="nav-item"><a href="/pages/294b0a/" class="nav-link">个人总结</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="来自大佬的文章" class="dropdown-title"><!----> <span class="title" style="display:;">来自大佬的文章</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>前端</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/pages/8143cc480faf9a11/" class="nav-link">前端文章</a></li><li class="dropdown-subitem"><a href="/note/javascript/" class="nav-link">学习笔记</a></li></ul></li><li class="dropdown-item"><h4>页面</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/pages/8309a5b876fc95e3/" class="nav-link">HTML</a></li><li class="dropdown-subitem"><a href="/pages/0a83b083bdf257cb/" class="nav-link">CSS</a></li></ul></li><li class="dropdown-item"><h4>技术</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/pages/9a7ee40fc232253e/" class="nav-link">技术文档</a></li><li class="dropdown-subitem"><a href="/pages/4c778760be26d8b3/" class="nav-link">GitHub技巧</a></li><li class="dropdown-subitem"><a href="/pages/117708e0af7f0bd9/" class="nav-link">Nodejs</a></li><li class="dropdown-subitem"><a href="/pages/41f87d890d0a02af/" class="nav-link">博客搭建</a></li></ul></li><li class="dropdown-item"><h4>更多</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/pages/f2a556/" class="nav-link">学习</a></li><li class="dropdown-subitem"><a href="/pages/aea6571b7a8bae86/" class="nav-link">面试</a></li><li class="dropdown-subitem"><a href="/pages/2d615df9a36a98ed/" class="nav-link">心情杂货</a></li><li class="dropdown-subitem"><a href="/pages/baaa02/" class="nav-link">实用技巧</a></li></ul></li><li class="dropdown-item"><!----> <a href="/about/" class="nav-link">关于</a></li><li class="dropdown-item"><!----> <a href="/pages/beb6c0bd8a66cea6/" class="nav-link">收藏</a></li><li class="dropdown-item"><h4>索引</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/categories/" class="nav-link">分类</a></li><li class="dropdown-subitem"><a href="/tags/" class="nav-link">标签</a></li><li class="dropdown-subitem"><a href="/archives/" class="nav-link">归档</a></li></ul></li></ul></div></div> <a href="https://github.com/yangkeith/vuepress-theme-vdoing" target="_blank" rel="noopener noreferrer" class="repo-link">
    GitHub
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar" style="display:none;"><div class="blogger"><img src="/img/avatar.jpg"> <div class="blogger-info"><h3>Keith</h3> <span>无名小卒</span></div></div> <nav class="nav-links"><div class="nav-item"><a href="/" class="nav-link">首页</a></div><div class="nav-item"><a href="/pages/294b0a/" class="nav-link">个人总结</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="来自大佬的文章" class="dropdown-title"><!----> <span class="title" style="display:;">来自大佬的文章</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>前端</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/pages/8143cc480faf9a11/" class="nav-link">前端文章</a></li><li class="dropdown-subitem"><a href="/note/javascript/" class="nav-link">学习笔记</a></li></ul></li><li class="dropdown-item"><h4>页面</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/pages/8309a5b876fc95e3/" class="nav-link">HTML</a></li><li class="dropdown-subitem"><a href="/pages/0a83b083bdf257cb/" class="nav-link">CSS</a></li></ul></li><li class="dropdown-item"><h4>技术</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/pages/9a7ee40fc232253e/" class="nav-link">技术文档</a></li><li class="dropdown-subitem"><a href="/pages/4c778760be26d8b3/" class="nav-link">GitHub技巧</a></li><li class="dropdown-subitem"><a href="/pages/117708e0af7f0bd9/" class="nav-link">Nodejs</a></li><li class="dropdown-subitem"><a href="/pages/41f87d890d0a02af/" class="nav-link">博客搭建</a></li></ul></li><li class="dropdown-item"><h4>更多</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/pages/f2a556/" class="nav-link">学习</a></li><li class="dropdown-subitem"><a href="/pages/aea6571b7a8bae86/" class="nav-link">面试</a></li><li class="dropdown-subitem"><a href="/pages/2d615df9a36a98ed/" class="nav-link">心情杂货</a></li><li class="dropdown-subitem"><a href="/pages/baaa02/" class="nav-link">实用技巧</a></li></ul></li><li class="dropdown-item"><!----> <a href="/about/" class="nav-link">关于</a></li><li class="dropdown-item"><!----> <a href="/pages/beb6c0bd8a66cea6/" class="nav-link">收藏</a></li><li class="dropdown-item"><h4>索引</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/categories/" class="nav-link">分类</a></li><li class="dropdown-subitem"><a href="/tags/" class="nav-link">标签</a></li><li class="dropdown-subitem"><a href="/archives/" class="nav-link">归档</a></li></ul></li></ul></div></div> <a href="https://github.com/yangkeith/vuepress-theme-vdoing" target="_blank" rel="noopener noreferrer" class="repo-link">
    GitHub
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav>  <ul class="sidebar-links"><li><a href="/pages/f344d070a1031ef7/" class="sidebar-link">ECMAScript 6 简介</a></li><li><a href="/pages/c1edd70a6b7c7872/" class="sidebar-link">let 和 const 命令</a></li><li><a href="/pages/b1ab10a62f7564da/" class="sidebar-link">变量的解构赋值</a></li><li><a href="/pages/ca89eca8adeba5f4/" class="sidebar-link">字符串的扩展</a></li><li><a href="/pages/a650b4a0ebfc9350/" class="sidebar-link">字符串的新增方法</a></li><li><a href="/pages/0473261a6ab0ee8c/" class="sidebar-link">正则的扩展</a></li><li><a href="/pages/5dfea9a0f2d1a392/" class="sidebar-link">数值的扩展</a></li><li><a href="/pages/8ed309d668b20264/" class="sidebar-link">函数的扩展</a></li><li><a href="/pages/e34009d60d8bc4b2/" class="sidebar-link">数组的扩展</a></li><li><a href="/pages/b5e3e0a0ff6e9c25/" class="sidebar-link">对象的扩展</a></li><li><a href="/pages/e85e68947502cf90/" class="sidebar-link">对象的新增方法</a></li><li><a href="/pages/02c86eb2792f3262/" aria-current="page" class="active sidebar-link">Symbol</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/pages/02c86eb2792f3262/#概述" class="sidebar-link">概述</a></li><li class="sidebar-sub-header"><a href="/pages/02c86eb2792f3262/#symbol-prototype-description" class="sidebar-link">Symbol.prototype.description</a></li><li class="sidebar-sub-header"><a href="/pages/02c86eb2792f3262/#作为属性名的-symbol" class="sidebar-link">作为属性名的 Symbol</a></li><li class="sidebar-sub-header"><a href="/pages/02c86eb2792f3262/#实例-消除魔术字符串" class="sidebar-link">实例：消除魔术字符串</a></li><li class="sidebar-sub-header"><a href="/pages/02c86eb2792f3262/#属性名的遍历" class="sidebar-link">属性名的遍历</a></li><li class="sidebar-sub-header"><a href="/pages/02c86eb2792f3262/#symbol-for-symbol-keyfor" class="sidebar-link">Symbol.for()，Symbol.keyFor()</a></li><li class="sidebar-sub-header"><a href="/pages/02c86eb2792f3262/#实例-模块的-singleton-模式" class="sidebar-link">实例：模块的 Singleton 模式</a></li><li class="sidebar-sub-header"><a href="/pages/02c86eb2792f3262/#内置的-symbol-值" class="sidebar-link">内置的 Symbol 值</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/pages/02c86eb2792f3262/#symbol-hasinstance" class="sidebar-link">Symbol.hasInstance</a></li><li class="sidebar-sub-header"><a href="/pages/02c86eb2792f3262/#symbol-isconcatspreadable" class="sidebar-link">Symbol.isConcatSpreadable</a></li><li class="sidebar-sub-header"><a href="/pages/02c86eb2792f3262/#symbol-species" class="sidebar-link">Symbol.species</a></li><li class="sidebar-sub-header"><a href="/pages/02c86eb2792f3262/#symbol-match" class="sidebar-link">Symbol.match</a></li><li class="sidebar-sub-header"><a href="/pages/02c86eb2792f3262/#symbol-replace" class="sidebar-link">Symbol.replace</a></li><li class="sidebar-sub-header"><a href="/pages/02c86eb2792f3262/#symbol-search" class="sidebar-link">Symbol.search</a></li><li class="sidebar-sub-header"><a href="/pages/02c86eb2792f3262/#symbol-split" class="sidebar-link">Symbol.split</a></li><li class="sidebar-sub-header"><a href="/pages/02c86eb2792f3262/#symbol-iterator" class="sidebar-link">Symbol.iterator</a></li><li class="sidebar-sub-header"><a href="/pages/02c86eb2792f3262/#symbol-toprimitive" class="sidebar-link">Symbol.toPrimitive</a></li><li class="sidebar-sub-header"><a href="/pages/02c86eb2792f3262/#symbol-tostringtag" class="sidebar-link">Symbol.toStringTag</a></li><li class="sidebar-sub-header"><a href="/pages/02c86eb2792f3262/#symbol-unscopables" class="sidebar-link">Symbol.unscopables</a></li></ul></li></ul></li><li><a href="/pages/0c21dae358fca16b/" class="sidebar-link">Set 和 Map 数据结构</a></li><li><a href="/pages/f56ec2ab97d60483/" class="sidebar-link">Proxy</a></li><li><a href="/pages/74de3e45e4491e95/" class="sidebar-link">Reflect</a></li><li><a href="/pages/2810ae8985e9bd52/" class="sidebar-link">Promise 对象</a></li><li><a href="/pages/48df907ad3570f3d/" class="sidebar-link">Iterator 和 for-of 循环</a></li><li><a href="/pages/718b48ed9ce0adce/" class="sidebar-link">Generator 函数的语法</a></li><li><a href="/pages/75af7031eb66847b/" class="sidebar-link">Generator 函数的异步应用</a></li><li><a href="/pages/3777253e65bac487/" class="sidebar-link">async 函数</a></li><li><a href="/pages/e831e1593c82bbe0/" class="sidebar-link">Class 的基本语法</a></li><li><a href="/pages/83f8c3a0cd87dd83/" class="sidebar-link">Class 的继承</a></li><li><a href="/pages/efe2fb04eb8ac5fb/" class="sidebar-link">Module 的语法</a></li><li><a href="/pages/a79ca2e64ceae213/" class="sidebar-link">Module 的加载实现</a></li><li><a href="/pages/984bf549204bb266/" class="sidebar-link">编程风格</a></li><li><a href="/pages/32c35f7651d6e58e/" class="sidebar-link">读懂 ECMAScript 规格</a></li><li><a href="/pages/16121351be68691b/" class="sidebar-link">异步遍历器</a></li><li><a href="/pages/a2ba314746bfdbdd/" class="sidebar-link">ArrayBuffer</a></li><li><a href="/pages/7188882b8d65af1b/" class="sidebar-link">最新提案</a></li><li><a href="/pages/e97bc1e5626b082c/" class="sidebar-link">装饰器</a></li><li><a href="/pages/1cf50330655efc69/" class="sidebar-link">函数式编程</a></li><li><a href="/pages/6a8e2dc558da1b39/" class="sidebar-link">Mixin</a></li><li><a href="/pages/8e8f80f69b775a56/" class="sidebar-link">SIMD</a></li><li><a href="/pages/ea6f3b870f6dab69/" class="sidebar-link">参考链接</a></li></ul> <div class="sidebar-slot sidebar-slot-bottom"><!-- 正方形 -->
      <ins class="adsbygoogle"
          style="display:block"
          data-ad-client="ca-pub-7828333725993554"
          data-ad-slot="3508773082"
          data-ad-format="auto"
          data-full-width-responsive="true"></ins>
      <script>
          (adsbygoogle = window.adsbygoogle || []).push({});
      </script></div></aside> <div><main class="page"><div class="theme-vdoing-wrapper "><div class="articleInfo-wrap" data-v-70a2d273><div class="articleInfo" data-v-70a2d273><ul class="breadcrumbs" data-v-70a2d273><li data-v-70a2d273><a href="/" title="首页" class="iconfont icon-home router-link-active" data-v-70a2d273></a></li> <li data-v-70a2d273><a href="/note/es6/" title="《ES6 教程》笔记-目录页" data-v-70a2d273>《ES6 教程》笔记</a></li> <!----> <!----></ul> <div class="info" data-v-70a2d273><div title="作者" class="author iconfont icon-touxiang" data-v-70a2d273><a href="javascript:;" data-v-70a2d273>阮一峰</a></div> <div title="创建时间" class="date iconfont icon-riqi" data-v-70a2d273><a href="javascript:;" data-v-70a2d273>2020-02-09</a></div> <!----></div></div></div> <!----> <div class="content-wrapper"><div class="right-menu-wrapper"><div class="right-menu-margin"><div class="right-menu-content"></div></div></div> <h1><img src="">
          Symbol
        </h1> <div class="page-slot page-slot-top"><!-- 固定100% * 90px可显示，max-height:90px未见显示-->
     <ins class="adsbygoogle"
          style="display:inline-block;width:100%;max-height:90px"
          data-ad-client="ca-pub-7828333725993554"
          data-ad-slot="6625304284"></ins>
      <script>
          (adsbygoogle = window.adsbygoogle || []).push({});
      </script></div> <div class="theme-vdoing-content content__default"><h1 id="symbol"><a href="#symbol" class="header-anchor">#</a> Symbol</h1> <h2 id="概述"><a href="#概述" class="header-anchor">#</a> 概述</h2> <p>ES5 的对象属性名都是字符串，这容易造成属性名的冲突。比如，你使用了一个他人提供的对象，但又想为这个对象添加新的方法（mixin 模式），新方法的名字就有可能与现有方法产生冲突。如果有一种机制，<strong>保证每个属性的名字都是独一无二</strong>的就好了，这样就从根本上防止属性名的冲突。这就是 ES6 引入<code>Symbol</code>的原因。
</p> <p>ES6 引入了一种新的<strong>原始数据类型<code>Symbol</code>，表示独一无二的值</strong>。它是 JavaScript 语言的第七种数据类型，前六种是：<code>undefined</code>、<code>null</code>、布尔值（Boolean）、字符串（String）、数值（Number）、对象（Object）。</p> <p><strong>Symbol 值通过<code>Symbol</code>函数生成</strong>。这就是说，**对象的属性名现在可以有两种类型，一种是原来就有的字符串，另一种就是新增的 Symbol 类型。**凡是属性名属于 Symbol 类型，就都是独一无二的，可以保证不会与其他属性名产生冲突。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">let</span> s <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">typeof</span> s
<span class="token comment">// &quot;symbol&quot;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><p>上面代码中，变量<code>s</code>就是一个独一无二的值。<code>typeof</code>运算符的结果，表明变量<code>s</code>是 Symbol 数据类型，而不是字符串之类的其他类型。</p> <p>注意，<strong><code>Symbol</code>函数前不能使用<code>new</code>命令，否则会报错</strong>。这是因为生成的 Symbol 是一个原始类型的值，不是对象。也就是说，由于 <strong>Symbol 值不是对象，所以不能添加属性</strong>。基本上，它是一种类似于字符串的数据类型。</p> <p><strong><code>Symbol</code>函数可以接受一个字符串作为参数</strong>，表示对 Symbol 实例的描述，主要是为了在控制台显示，或者转为字符串时，比较容易区分。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">let</span> s1 <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token string">'foo'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> s2 <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token string">'bar'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

s1 <span class="token comment">// Symbol(foo)</span>
s2 <span class="token comment">// Symbol(bar)</span>

s1<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// &quot;Symbol(foo)&quot;</span>
s2<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// &quot;Symbol(bar)&quot;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><p>上面代码中，<code>s1</code>和<code>s2</code>是两个 Symbol 值。如果不加参数，它们在控制台的输出都是<code>Symbol()</code>，不利于区分。有了参数以后，就等于为它们加上了描述，输出的时候就能够分清，到底是哪一个值。</p> <p>如果 <strong>Symbol 的参数是一个对象，就会调用该对象的<code>toString</code>方法，将其转为字符串</strong>，然后才生成一个 Symbol 值。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token string">'abc'</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> sym <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span><span class="token punctuation">;</span>
sym <span class="token comment">// Symbol(abc)</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><p>注意，<strong><code>Symbol</code>函数的参数只是表示对当前 Symbol 值的描述，因此相同参数的<code>Symbol</code>函数的返回值是不相等的。</strong></p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token comment">// 没有参数的情况</span>
<span class="token keyword">let</span> s1 <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> s2 <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

s1 <span class="token operator">===</span> s2 <span class="token comment">// false</span>

<span class="token comment">// 有参数的情况</span>
<span class="token keyword">let</span> s1 <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token string">'foo'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> s2 <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token string">'foo'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

s1 <span class="token operator">===</span> s2 <span class="token comment">// false</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br></div></div><p>上面代码中，<code>s1</code>和<code>s2</code>都是<code>Symbol</code>函数的返回值，而且参数相同，但是它们是<strong>不相等的</strong>。</p> <p>Symbol 值<strong>不能与其他类型的值进行运算</strong>，会报错。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">let</span> sym <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token string">'My symbol'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token string">&quot;your symbol is &quot;</span> <span class="token operator">+</span> sym
<span class="token comment">// TypeError: can't convert symbol to string</span>
<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">your symbol is </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>sym<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span>
<span class="token comment">// TypeError: can't convert symbol to string</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><p>但是，<strong>Symbol 值可以显式转为字符串</strong>。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">let</span> sym <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token string">'My symbol'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token function">String</span><span class="token punctuation">(</span>sym<span class="token punctuation">)</span> <span class="token comment">// 'Symbol(My symbol)'</span>
sym<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 'Symbol(My symbol)'</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><p>另外，<strong>Symbol 值也可以转为布尔值，但是不能转为数值</strong>。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">let</span> sym <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">Boolean</span><span class="token punctuation">(</span>sym<span class="token punctuation">)</span> <span class="token comment">// true</span>
<span class="token operator">!</span>sym  <span class="token comment">// false</span>

<span class="token keyword">if</span> <span class="token punctuation">(</span>sym<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// ...</span>
<span class="token punctuation">}</span>

<span class="token function">Number</span><span class="token punctuation">(</span>sym<span class="token punctuation">)</span> <span class="token comment">// TypeError</span>
sym <span class="token operator">+</span> <span class="token number">2</span> <span class="token comment">// TypeError</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><h2 id="symbol-prototype-description"><a href="#symbol-prototype-description" class="header-anchor">#</a> Symbol.prototype.description</h2> <p>创建 Symbol 的时候，可以添加一个描述。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">const</span> sym <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token string">'foo'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>上面代码中，<code>sym</code>的描述就是字符串<code>foo</code>。</p> <p>但是，读取这个描述需要将 Symbol 显式转为字符串，即下面的写法。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">const</span> sym <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token string">'foo'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token function">String</span><span class="token punctuation">(</span>sym<span class="token punctuation">)</span> <span class="token comment">// &quot;Symbol(foo)&quot;</span>
sym<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// &quot;Symbol(foo)&quot;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><p>上面的用法不是很方便。<a href="https://github.com/tc39/proposal-Symbol-description" target="_blank" rel="noopener noreferrer">ES2019<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> 提供了一个实例属性<code>description</code>，直接返回 Symbol 的描述。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">const</span> sym <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token string">'foo'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

sym<span class="token punctuation">.</span>description <span class="token comment">// &quot;foo&quot;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><h2 id="作为属性名的-symbol"><a href="#作为属性名的-symbol" class="header-anchor">#</a> 作为属性名的 Symbol</h2> <p>由于每一个 Symbol 值都是不相等的，这意味着 Symbol 值可以作为标识符，用于对象的属性名，就能保证不会出现同名的属性。这对于一个对象由多个模块构成的情况非常有用，能防止某一个键被不小心改写或覆盖。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">let</span> mySymbol <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 第一种写法</span>
<span class="token keyword">let</span> a <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
a<span class="token punctuation">[</span>mySymbol<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token string">'Hello!'</span><span class="token punctuation">;</span>

<span class="token comment">// 第二种写法</span>
<span class="token keyword">let</span> a <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token punctuation">[</span>mySymbol<span class="token punctuation">]</span><span class="token operator">:</span> <span class="token string">'Hello!'</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token comment">// 第三种写法</span>
<span class="token keyword">let</span> a <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
Object<span class="token punctuation">.</span><span class="token function">defineProperty</span><span class="token punctuation">(</span>a<span class="token punctuation">,</span> mySymbol<span class="token punctuation">,</span> <span class="token punctuation">{</span> value<span class="token operator">:</span> <span class="token string">'Hello!'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 以上写法都得到同样结果</span>
a<span class="token punctuation">[</span>mySymbol<span class="token punctuation">]</span> <span class="token comment">// &quot;Hello!&quot;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br></div></div><p>上面代码<strong>通过方括号结构和<code>Object.defineProperty</code>，将对象的属性名指定为一个 Symbol 值</strong>。</p> <p>注意，Symbol 值作为对象属性名时，不能用点运算符。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">const</span> mySymbol <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> a <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>

a<span class="token punctuation">.</span>mySymbol <span class="token operator">=</span> <span class="token string">'Hello!'</span><span class="token punctuation">;</span>
a<span class="token punctuation">[</span>mySymbol<span class="token punctuation">]</span> <span class="token comment">// undefined</span>
a<span class="token punctuation">[</span><span class="token string">'mySymbol'</span><span class="token punctuation">]</span> <span class="token comment">// &quot;Hello!&quot;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><p>上面代码中，因为点运算符后面总是字符串，所以不会读取<code>mySymbol</code>作为标识名所指代的那个值，导致<code>a</code>的属性名实际上是一个字符串，而不是一个 Symbol 值。</p> <p>同理，在对象的内部，使用 Symbol 值定义属性时，Symbol 值必须放在方括号之中。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">let</span> s <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">let</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token punctuation">[</span>s<span class="token punctuation">]</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">arg</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

obj<span class="token punctuation">[</span>s<span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token number">123</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><p>上面代码中，如果<code>s</code>不放在方括号中，该属性的键名就是字符串<code>s</code>，而不是<code>s</code>所代表的那个 Symbol 值。</p> <p>采用增强的对象写法，上面代码的<code>obj</code>对象可以写得更简洁一些。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">let</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token punctuation">[</span>s<span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token parameter">arg</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>Symbol 类型还可以用于定义一组常量，保证这组常量的值都是不相等的。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">const</span> log <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>

log<span class="token punctuation">.</span>levels <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token constant">DEBUG</span><span class="token operator">:</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token string">'debug'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token constant">INFO</span><span class="token operator">:</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token string">'info'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token constant">WARN</span><span class="token operator">:</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token string">'warn'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>log<span class="token punctuation">.</span>levels<span class="token punctuation">.</span><span class="token constant">DEBUG</span><span class="token punctuation">,</span> <span class="token string">'debug message'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>log<span class="token punctuation">.</span>levels<span class="token punctuation">.</span><span class="token constant">INFO</span><span class="token punctuation">,</span> <span class="token string">'info message'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><p>下面是另外一个例子。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">const</span> <span class="token constant">COLOR_RED</span>    <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token constant">COLOR_GREEN</span>  <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">getComplement</span><span class="token punctuation">(</span><span class="token parameter">color</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">switch</span> <span class="token punctuation">(</span>color<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">case</span> <span class="token constant">COLOR_RED</span><span class="token operator">:</span>
      <span class="token keyword">return</span> <span class="token constant">COLOR_GREEN</span><span class="token punctuation">;</span>
    <span class="token keyword">case</span> <span class="token constant">COLOR_GREEN</span><span class="token operator">:</span>
      <span class="token keyword">return</span> <span class="token constant">COLOR_RED</span><span class="token punctuation">;</span>
    <span class="token keyword">default</span><span class="token operator">:</span>
      <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">'Undefined color'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br></div></div><p>常量使用 Symbol 值最大的好处，就是其他任何值都不可能有相同的值了，因此可以保证上面的<code>switch</code>语句会按设计的方式工作。</p> <p>还有一点需要注意，Symbol 值作为属性名时，该属性还是公开属性，不是私有属性。</p> <h2 id="实例-消除魔术字符串"><a href="#实例-消除魔术字符串" class="header-anchor">#</a> 实例：消除魔术字符串</h2> <p><strong>魔术字符串指的是，在代码之中多次出现、与代码形成强耦合的某一个具体的字符串或者数值</strong>。风格良好的代码，应该尽量消除魔术字符串，改由含义清晰的变量代替。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">function</span> <span class="token function">getArea</span><span class="token punctuation">(</span><span class="token parameter">shape<span class="token punctuation">,</span> options</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> area <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>

  <span class="token keyword">switch</span> <span class="token punctuation">(</span>shape<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">case</span> <span class="token string">'Triangle'</span><span class="token operator">:</span> <span class="token comment">// 魔术字符串</span>
      area <span class="token operator">=</span> <span class="token number">.5</span> <span class="token operator">*</span> options<span class="token punctuation">.</span>width <span class="token operator">*</span> options<span class="token punctuation">.</span>height<span class="token punctuation">;</span>
      <span class="token keyword">break</span><span class="token punctuation">;</span>
    <span class="token comment">/* ... more code ... */</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">return</span> area<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">getArea</span><span class="token punctuation">(</span><span class="token string">'Triangle'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> width<span class="token operator">:</span> <span class="token number">100</span><span class="token punctuation">,</span> height<span class="token operator">:</span> <span class="token number">100</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 魔术字符串</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br></div></div><p>上面代码中，字符串<code>Triangle</code>就是一个魔术字符串。它多次出现，与代码形成“强耦合”，不利于将来的修改和维护。</p> <blockquote><p>笔记：</p> <p><code>Triangle</code>字符串在代码中出现多次，如果后期想修改这个字符串需要修改很多处，不利于维护。</p></blockquote> <p>常用的消除魔术字符串的方法，就是把它写成一个变量。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">const</span> shapeType <span class="token operator">=</span> <span class="token punctuation">{</span>
  triangle<span class="token operator">:</span> <span class="token string">'Triangle'</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">getArea</span><span class="token punctuation">(</span><span class="token parameter">shape<span class="token punctuation">,</span> options</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> area <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
  <span class="token keyword">switch</span> <span class="token punctuation">(</span>shape<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">case</span> shapeType<span class="token punctuation">.</span>triangle<span class="token operator">:</span>
      area <span class="token operator">=</span> <span class="token number">.5</span> <span class="token operator">*</span> options<span class="token punctuation">.</span>width <span class="token operator">*</span> options<span class="token punctuation">.</span>height<span class="token punctuation">;</span>
      <span class="token keyword">break</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">return</span> area<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">getArea</span><span class="token punctuation">(</span>shapeType<span class="token punctuation">.</span>triangle<span class="token punctuation">,</span> <span class="token punctuation">{</span> width<span class="token operator">:</span> <span class="token number">100</span><span class="token punctuation">,</span> height<span class="token operator">:</span> <span class="token number">100</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br></div></div><p>上面代码中，我们把<code>Triangle</code>写成<code>shapeType</code>对象的<code>triangle</code>属性，这样就消除了强耦合。</p> <p>如果仔细分析，可以发现<code>shapeType.triangle</code><strong>等于哪个值并不重要，只要确保不会跟其他<code>shapeType</code>属性的值冲突即可。因此，这里就很适合改用 Symbol 值</strong>。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">const</span> shapeType <span class="token operator">=</span> <span class="token punctuation">{</span>
  triangle<span class="token operator">:</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>上面代码中，除了将<code>shapeType.triangle</code>的值设为一个 Symbol，其他地方都不用修改。</p> <h2 id="属性名的遍历"><a href="#属性名的遍历" class="header-anchor">#</a> 属性名的遍历</h2> <p><strong>Symbol 作为属性名，遍历对象的时候，该属性不会出现在<code>for...in</code>、<code>for...of</code>循环中，也不会被<code>Object.keys()</code>、<code>Object.getOwnPropertyNames()</code>、<code>JSON.stringify()</code>返回</strong>。</p> <p>但是，它也不是私有属性，有一个**<code>Object.getOwnPropertySymbols()</code>方法，可以获取指定对象的所有 Symbol 属性名**。该方法返回一个数组，成员是当前对象的所有用作属性名的 Symbol 值。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> a <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token string">'a'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> b <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token string">'b'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

obj<span class="token punctuation">[</span>a<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token string">'Hello'</span><span class="token punctuation">;</span>
obj<span class="token punctuation">[</span>b<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token string">'World'</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> objectSymbols <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">getOwnPropertySymbols</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span><span class="token punctuation">;</span>

objectSymbols
<span class="token comment">// [Symbol(a), Symbol(b)]</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br></div></div><p>上面代码是<code>Object.getOwnPropertySymbols()</code>方法的示例，可以获取所有 Symbol 属性名。</p> <p>下面是另一个例子，<code>Object.getOwnPropertySymbols()</code>方法与<code>for...in</code>循环、<code>Object.getOwnPropertyNames</code>方法进行对比的例子。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> foo <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token string">'foo'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

obj<span class="token punctuation">[</span>foo<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token string">'bar'</span><span class="token punctuation">;</span>

<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token keyword">in</span> obj<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 无输出</span>
<span class="token punctuation">}</span>

Object<span class="token punctuation">.</span><span class="token function">getOwnPropertyNames</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span> <span class="token comment">// []</span>
Object<span class="token punctuation">.</span><span class="token function">getOwnPropertySymbols</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span> <span class="token comment">// [Symbol(foo)]</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br></div></div><p>上面代码中，使用<code>for...in</code>循环和<code>Object.getOwnPropertyNames()</code>方法都得不到 Symbol 键名，需要使用<code>Object.getOwnPropertySymbols()</code>方法。</p> <p>另一个新的 API，<code>Reflect.ownKeys()</code>方法可以返回所有类型的键名，包括常规键名和 Symbol 键名。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">let</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token punctuation">[</span><span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token string">'my_key'</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
  <span class="token keyword">enum</span><span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span>
  nonEnum<span class="token operator">:</span> <span class="token number">3</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

Reflect<span class="token punctuation">.</span><span class="token function">ownKeys</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span>
<span class="token comment">//  [&quot;enum&quot;, &quot;nonEnum&quot;, Symbol(my_key)]</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><p>由于以 Symbol 值作为键名，不会被常规方法遍历得到。我们可以利用这个特性，<strong>为对象定义一些非私有的、但又希望只用于内部的方法</strong>。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">let</span> size <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token string">'size'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">class</span> <span class="token class-name">Collection</span> <span class="token punctuation">{</span>
  <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">[</span>size<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token function">add</span><span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">[</span><span class="token keyword">this</span><span class="token punctuation">[</span>size<span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">=</span> item<span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">[</span>size<span class="token punctuation">]</span><span class="token operator">++</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">static</span> <span class="token function">sizeOf</span><span class="token punctuation">(</span><span class="token parameter">instance</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> instance<span class="token punctuation">[</span>size<span class="token punctuation">]</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">let</span> x <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Collection</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
Collection<span class="token punctuation">.</span><span class="token function">sizeOf</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span> <span class="token comment">// 0</span>

x<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">'foo'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
Collection<span class="token punctuation">.</span><span class="token function">sizeOf</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span> <span class="token comment">// 1</span>

Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span> <span class="token comment">// ['0']</span>
Object<span class="token punctuation">.</span><span class="token function">getOwnPropertyNames</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span> <span class="token comment">// ['0']</span>
Object<span class="token punctuation">.</span><span class="token function">getOwnPropertySymbols</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span> <span class="token comment">// [Symbol(size)]</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br></div></div><p>上面代码中，对象<code>x</code>的<code>size</code>属性是一个 Symbol 值，所以<code>Object.keys(x)</code>、<code>Object.getOwnPropertyNames(x)</code>都无法获取它。这就造成了一种非私有的内部方法的效果。</p> <h2 id="symbol-for-symbol-keyfor"><a href="#symbol-for-symbol-keyfor" class="header-anchor">#</a> Symbol.for()，Symbol.keyFor()</h2> <p>有时，我们希望重新使用同一个 Symbol 值，<code>Symbol.for()</code>方法可以做到这一点。它接受一个字符串作为参数，然后搜索有没有以该参数作为名称的 Symbol 值。如果有，就返回这个 Symbol 值，否则就新建一个以该字符串为名称的 Symbol 值，并将其注册到全局。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">let</span> s1 <span class="token operator">=</span> Symbol<span class="token punctuation">.</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token string">'foo'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> s2 <span class="token operator">=</span> Symbol<span class="token punctuation">.</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token string">'foo'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

s1 <span class="token operator">===</span> s2 <span class="token comment">// true</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><p>上面代码中，<code>s1</code>和<code>s2</code>都是 Symbol 值，但是它们都是同样参数的<code>Symbol.for</code>方法生成的，所以实际上是同一个值。</p> <p><code>Symbol.for()</code>与<code>Symbol()</code>这两种写法，都会生成新的 Symbol。它们的区别是，前者会被登记在全局环境中供搜索，后者不会。<strong><code>Symbol.for()</code>不会每次调用就返回一个新的 Symbol 类型的值，而是会先检查给定的<code>key</code>是否已经存在，如果不存在才会新建一个值</strong>。比如，如果你调用<code>Symbol.for(&quot;cat&quot;)</code>30 次，每次都会返回同一个 Symbol 值，但是调用<code>Symbol(&quot;cat&quot;)</code>30 次，会返回 30 个不同的 Symbol 值。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code>Symbol<span class="token punctuation">.</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token string">&quot;bar&quot;</span><span class="token punctuation">)</span> <span class="token operator">===</span> Symbol<span class="token punctuation">.</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token string">&quot;bar&quot;</span><span class="token punctuation">)</span>
<span class="token comment">// true</span>

<span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token string">&quot;bar&quot;</span><span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token string">&quot;bar&quot;</span><span class="token punctuation">)</span>
<span class="token comment">// false</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>上面代码中，由于<code>Symbol()</code>写法没有登记机制，所以每次调用都会返回一个不同的值。</p> <p><code>Symbol.keyFor()</code>方法返回一个已登记的 Symbol 类型值的<code>key</code>。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">let</span> s1 <span class="token operator">=</span> Symbol<span class="token punctuation">.</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token string">&quot;foo&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
Symbol<span class="token punctuation">.</span><span class="token function">keyFor</span><span class="token punctuation">(</span>s1<span class="token punctuation">)</span> <span class="token comment">// &quot;foo&quot;</span>

<span class="token keyword">let</span> s2 <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token string">&quot;foo&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
Symbol<span class="token punctuation">.</span><span class="token function">keyFor</span><span class="token punctuation">(</span>s2<span class="token punctuation">)</span> <span class="token comment">// undefined</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>上面代码中，变量<code>s2</code>属于未登记的 Symbol 值，所以返回<code>undefined</code>。</p> <p>注意，<strong><code>Symbol.for()</code>为 Symbol 值登记的名字，是全局环境的，不管有没有在全局环境运行。</strong></p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">function</span> <span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> Symbol<span class="token punctuation">.</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token string">'bar'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">const</span> x <span class="token operator">=</span> <span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> y <span class="token operator">=</span> Symbol<span class="token punctuation">.</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token string">'bar'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>x <span class="token operator">===</span> y<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// true</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><p>上面代码中，<code>Symbol.for('bar')</code>是函数内部运行的，但是生成的 Symbol 值是登记在全局环境的。所以，第二次运行<code>Symbol.for('bar')</code>可以取到这个 Symbol 值。</p> <p><code>Symbol.for()</code>的这个全局登记特性，可以用在不同的 iframe 或 service worker 中取到同一个值。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code>iframe <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'iframe'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
iframe<span class="token punctuation">.</span>src <span class="token operator">=</span> <span class="token function">String</span><span class="token punctuation">(</span>window<span class="token punctuation">.</span>location<span class="token punctuation">)</span><span class="token punctuation">;</span>
document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>iframe<span class="token punctuation">)</span><span class="token punctuation">;</span>

iframe<span class="token punctuation">.</span>contentWindow<span class="token punctuation">.</span>Symbol<span class="token punctuation">.</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token string">'foo'</span><span class="token punctuation">)</span> <span class="token operator">===</span> Symbol<span class="token punctuation">.</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token string">'foo'</span><span class="token punctuation">)</span>
<span class="token comment">// true</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><p>上面代码中，iframe 窗口生成的 Symbol 值，可以在主页面得到。</p> <h2 id="实例-模块的-singleton-模式"><a href="#实例-模块的-singleton-模式" class="header-anchor">#</a> 实例：模块的 Singleton 模式</h2> <p>Singleton 模式指的是调用一个类，任何时候返回的都是同一个实例。</p> <p>对于 Node 来说，模块文件可以看成是一个类。怎么保证每次执行这个模块文件，返回的都是同一个实例呢？</p> <p>很容易想到，可以把实例放到顶层对象<code>global</code>。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token comment">// mod.js</span>
<span class="token keyword">function</span> <span class="token constant">A</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>foo <span class="token operator">=</span> <span class="token string">'hello'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>global<span class="token punctuation">.</span>_foo<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  global<span class="token punctuation">.</span>_foo <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">A</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

module<span class="token punctuation">.</span>exports <span class="token operator">=</span> global<span class="token punctuation">.</span>_foo<span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><p>然后，加载上面的<code>mod.js</code>。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">const</span> a <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./mod.js'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>a<span class="token punctuation">.</span>foo<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p>上面代码中，变量<code>a</code>任何时候加载的都是<code>A</code>的同一个实例。</p> <p>但是，这里有一个问题，全局变量<code>global._foo</code>是可写的，任何文件都可以修改。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code>global<span class="token punctuation">.</span>_foo <span class="token operator">=</span> <span class="token punctuation">{</span> foo<span class="token operator">:</span> <span class="token string">'world'</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> a <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./mod.js'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>a<span class="token punctuation">.</span>foo<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><p>上面的代码，会使得加载<code>mod.js</code>的脚本都失真。</p> <p>为了防止这种情况出现，我们就可以使用 Symbol。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token comment">// mod.js</span>
<span class="token keyword">const</span> <span class="token constant">FOO_KEY</span> <span class="token operator">=</span> Symbol<span class="token punctuation">.</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token string">'foo'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token constant">A</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>foo <span class="token operator">=</span> <span class="token string">'hello'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>global<span class="token punctuation">[</span><span class="token constant">FOO_KEY</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  global<span class="token punctuation">[</span><span class="token constant">FOO_KEY</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">A</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

module<span class="token punctuation">.</span>exports <span class="token operator">=</span> global<span class="token punctuation">[</span><span class="token constant">FOO_KEY</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><p>上面代码中，可以保证<code>global[FOO_KEY]</code>不会被无意间覆盖，但还是可以被改写。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code>global<span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token string">'foo'</span><span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">{</span> foo<span class="token operator">:</span> <span class="token string">'world'</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> a <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./mod.js'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>如果键名使用<code>Symbol</code>方法生成，那么外部将无法引用这个值，当然也就无法改写。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token comment">// mod.js</span>
<span class="token keyword">const</span> <span class="token constant">FOO_KEY</span> <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token string">'foo'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 后面代码相同 ……</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><p>上面代码将导致其他脚本都无法引用<code>FOO_KEY</code>。但这样也有一个问题，就是如果多次执行这个脚本，每次得到的<code>FOO_KEY</code>都是不一样的。虽然 Node 会将脚本的执行结果缓存，一般情况下，不会多次执行同一个脚本，但是用户可以手动清除缓存，所以也不是绝对可靠。</p> <h2 id="内置的-symbol-值"><a href="#内置的-symbol-值" class="header-anchor">#</a> 内置的 Symbol 值</h2> <p>除了定义自己使用的 Symbol 值以外，ES6 还提供了 11 个内置的 Symbol 值，指向语言内部使用的方法。</p> <h3 id="symbol-hasinstance"><a href="#symbol-hasinstance" class="header-anchor">#</a> Symbol.hasInstance</h3> <p>对象的<code>Symbol.hasInstance</code>属性，指向一个内部方法。当其他对象使用<code>instanceof</code>运算符，判断是否为该对象的实例时，会调用这个方法。比如，<code>foo instanceof Foo</code>在语言内部，实际调用的是<code>Foo[Symbol.hasInstance](foo)</code>。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">class</span> <span class="token class-name">MyClass</span> <span class="token punctuation">{</span>
  <span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>hasInstance<span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token parameter">foo</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> foo <span class="token keyword">instanceof</span> <span class="token class-name">Array</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span> <span class="token keyword">instanceof</span> <span class="token class-name">new</span> <span class="token function">MyClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// true</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><p>上面代码中，<code>MyClass</code>是一个类，<code>new MyClass()</code>会返回一个实例。该实例的<code>Symbol.hasInstance</code>方法，会在进行<code>instanceof</code>运算时自动调用，判断左侧的运算子是否为<code>Array</code>的实例。</p> <p>下面是另一个例子。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">class</span> <span class="token class-name">Even</span> <span class="token punctuation">{</span>
  <span class="token keyword">static</span> <span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>hasInstance<span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token parameter">obj</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token function">Number</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span> <span class="token operator">%</span> <span class="token number">2</span> <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token comment">// 等同于</span>
<span class="token keyword">const</span> Even <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>hasInstance<span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token parameter">obj</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token function">Number</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span> <span class="token operator">%</span> <span class="token number">2</span> <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token number">1</span> <span class="token keyword">instanceof</span> <span class="token class-name">Even</span> <span class="token comment">// false</span>
<span class="token number">2</span> <span class="token keyword">instanceof</span> <span class="token class-name">Even</span> <span class="token comment">// true</span>
<span class="token number">12345</span> <span class="token keyword">instanceof</span> <span class="token class-name">Even</span> <span class="token comment">// false</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br></div></div><h3 id="symbol-isconcatspreadable"><a href="#symbol-isconcatspreadable" class="header-anchor">#</a> Symbol.isConcatSpreadable</h3> <p>对象的<code>Symbol.isConcatSpreadable</code>属性等于一个布尔值，表示该对象用于<code>Array.prototype.concat()</code>时，是否可以展开。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">let</span> arr1 <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'c'</span><span class="token punctuation">,</span> <span class="token string">'d'</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">[</span><span class="token string">'a'</span><span class="token punctuation">,</span> <span class="token string">'b'</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">(</span>arr1<span class="token punctuation">,</span> <span class="token string">'e'</span><span class="token punctuation">)</span> <span class="token comment">// ['a', 'b', 'c', 'd', 'e']</span>
arr1<span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>isConcatSpreadable<span class="token punctuation">]</span> <span class="token comment">// undefined</span>

<span class="token keyword">let</span> arr2 <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'c'</span><span class="token punctuation">,</span> <span class="token string">'d'</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
arr2<span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>isConcatSpreadable<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token punctuation">[</span><span class="token string">'a'</span><span class="token punctuation">,</span> <span class="token string">'b'</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">(</span>arr2<span class="token punctuation">,</span> <span class="token string">'e'</span><span class="token punctuation">)</span> <span class="token comment">// ['a', 'b', ['c','d'], 'e']</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><p>上面代码说明，数组的默认行为是可以展开，<code>Symbol.isConcatSpreadable</code>默认等于<code>undefined</code>。该属性等于<code>true</code>时，也有展开的效果。</p> <p>类似数组的对象正好相反，默认不展开。它的<code>Symbol.isConcatSpreadable</code>属性设为<code>true</code>，才可以展开。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">let</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span>length<span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token operator">:</span> <span class="token string">'c'</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token operator">:</span> <span class="token string">'d'</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">[</span><span class="token string">'a'</span><span class="token punctuation">,</span> <span class="token string">'b'</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> <span class="token string">'e'</span><span class="token punctuation">)</span> <span class="token comment">// ['a', 'b', obj, 'e']</span>

obj<span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>isConcatSpreadable<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
<span class="token punctuation">[</span><span class="token string">'a'</span><span class="token punctuation">,</span> <span class="token string">'b'</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> <span class="token string">'e'</span><span class="token punctuation">)</span> <span class="token comment">// ['a', 'b', 'c', 'd', 'e']</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p><code>Symbol.isConcatSpreadable</code>属性也可以定义在类里面。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">class</span> <span class="token class-name">A1</span> <span class="token keyword">extends</span> <span class="token class-name">Array</span> <span class="token punctuation">{</span>
  <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">args</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">super</span><span class="token punctuation">(</span>args<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>isConcatSpreadable<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">class</span> <span class="token class-name">A2</span> <span class="token keyword">extends</span> <span class="token class-name">Array</span> <span class="token punctuation">{</span>
  <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">args</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">super</span><span class="token punctuation">(</span>args<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">get</span> <span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>isConcatSpreadable<span class="token punctuation">]</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">let</span> a1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">A1</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
a1<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token number">3</span><span class="token punctuation">;</span>
a1<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token number">4</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> a2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">A2</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
a2<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token number">5</span><span class="token punctuation">;</span>
a2<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token number">6</span><span class="token punctuation">;</span>
<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">(</span>a1<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">(</span>a2<span class="token punctuation">)</span>
<span class="token comment">// [1, 2, 3, 4, [5, 6]]</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br></div></div><p>上面代码中，类<code>A1</code>是可展开的，类<code>A2</code>是不可展开的，所以使用<code>concat</code>时有不一样的结果。</p> <p>注意，<code>Symbol.isConcatSpreadable</code>的位置差异，<code>A1</code>是定义在实例上，<code>A2</code>是定义在类本身，效果相同。</p> <h3 id="symbol-species"><a href="#symbol-species" class="header-anchor">#</a> Symbol.species</h3> <p>对象的<code>Symbol.species</code>属性，指向一个构造函数。创建衍生对象时，会使用该属性。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">class</span> <span class="token class-name">MyArray</span> <span class="token keyword">extends</span> <span class="token class-name">Array</span> <span class="token punctuation">{</span>
<span class="token punctuation">}</span>

<span class="token keyword">const</span> a <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MyArray</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> b <span class="token operator">=</span> a<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">x</span> <span class="token operator">=&gt;</span> x<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> c <span class="token operator">=</span> a<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token parameter">x</span> <span class="token operator">=&gt;</span> x <span class="token operator">&gt;</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

b <span class="token keyword">instanceof</span> <span class="token class-name">MyArray</span> <span class="token comment">// true</span>
c <span class="token keyword">instanceof</span> <span class="token class-name">MyArray</span> <span class="token comment">// true</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><p>上面代码中，子类<code>MyArray</code>继承了父类<code>Array</code>，<code>a</code>是<code>MyArray</code>的实例，<code>b</code>和<code>c</code>是<code>a</code>的衍生对象。你可能会认为，<code>b</code>和<code>c</code>都是调用数组方法生成的，所以应该是数组（<code>Array</code>的实例），但实际上它们也是<code>MyArray</code>的实例。</p> <p><code>Symbol.species</code>属性就是为了解决这个问题而提供的。现在，我们可以为<code>MyArray</code>设置<code>Symbol.species</code>属性。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">class</span> <span class="token class-name">MyArray</span> <span class="token keyword">extends</span> <span class="token class-name">Array</span> <span class="token punctuation">{</span>
  <span class="token keyword">static</span> <span class="token keyword">get</span> <span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>species<span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> Array<span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>上面代码中，由于定义了<code>Symbol.species</code>属性，创建衍生对象时就会使用这个属性返回的函数，作为构造函数。这个例子也说明，定义<code>Symbol.species</code>属性要采用<code>get</code>取值器。默认的<code>Symbol.species</code>属性等同于下面的写法。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">static</span> <span class="token keyword">get</span> <span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>species<span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>现在，再来看前面的例子。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">class</span> <span class="token class-name">MyArray</span> <span class="token keyword">extends</span> <span class="token class-name">Array</span> <span class="token punctuation">{</span>
  <span class="token keyword">static</span> <span class="token keyword">get</span> <span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>species<span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> Array<span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">const</span> a <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MyArray</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> b <span class="token operator">=</span> a<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">x</span> <span class="token operator">=&gt;</span> x<span class="token punctuation">)</span><span class="token punctuation">;</span>

b <span class="token keyword">instanceof</span> <span class="token class-name">MyArray</span> <span class="token comment">// false</span>
b <span class="token keyword">instanceof</span> <span class="token class-name">Array</span> <span class="token comment">// true</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><p>上面代码中，<code>a.map(x =&gt; x)</code>生成的衍生对象，就不是<code>MyArray</code>的实例，而直接就是<code>Array</code>的实例。</p> <p>再看一个例子。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">class</span> <span class="token class-name">T1</span> <span class="token keyword">extends</span> <span class="token class-name">Promise</span> <span class="token punctuation">{</span>
<span class="token punctuation">}</span>

<span class="token keyword">class</span> <span class="token class-name">T2</span> <span class="token keyword">extends</span> <span class="token class-name">Promise</span> <span class="token punctuation">{</span>
  <span class="token keyword">static</span> <span class="token keyword">get</span> <span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>species<span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> Promise<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">new</span> <span class="token class-name">T1</span><span class="token punctuation">(</span><span class="token parameter">r</span> <span class="token operator">=&gt;</span> <span class="token function">r</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">v</span> <span class="token operator">=&gt;</span> v<span class="token punctuation">)</span> <span class="token keyword">instanceof</span> <span class="token class-name">T1</span> <span class="token comment">// true</span>
<span class="token keyword">new</span> <span class="token class-name">T2</span><span class="token punctuation">(</span><span class="token parameter">r</span> <span class="token operator">=&gt;</span> <span class="token function">r</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">v</span> <span class="token operator">=&gt;</span> v<span class="token punctuation">)</span> <span class="token keyword">instanceof</span> <span class="token class-name">T2</span> <span class="token comment">// false</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br></div></div><p>上面代码中，<code>T2</code>定义了<code>Symbol.species</code>属性，<code>T1</code>没有。结果就导致了创建衍生对象时（<code>then</code>方法），<code>T1</code>调用的是自身的构造方法，而<code>T2</code>调用的是<code>Promise</code>的构造方法。</p> <p>总之，<code>Symbol.species</code>的作用在于，实例对象在运行过程中，需要再次调用自身的构造函数时，会调用该属性指定的构造函数。它主要的用途是，有些类库是在基类的基础上修改的，那么子类使用继承的方法时，作者可能希望返回基类的实例，而不是子类的实例。</p> <h3 id="symbol-match"><a href="#symbol-match" class="header-anchor">#</a> Symbol.match</h3> <p>对象的<code>Symbol.match</code>属性，指向一个函数。当执行<code>str.match(myObject)</code>时，如果该属性存在，会调用它，返回该方法的返回值。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token class-name">String</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function">match</span><span class="token punctuation">(</span>regexp<span class="token punctuation">)</span>
<span class="token comment">// 等同于</span>
regexp<span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>match<span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span>

<span class="token keyword">class</span> <span class="token class-name">MyMatcher</span> <span class="token punctuation">{</span>
  <span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>match<span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token parameter">string</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token string">'hello world'</span><span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span>string<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token string">'e'</span><span class="token punctuation">.</span><span class="token function">match</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">MyMatcher</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// 1</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br></div></div><h3 id="symbol-replace"><a href="#symbol-replace" class="header-anchor">#</a> Symbol.replace</h3> <p>对象的<code>Symbol.replace</code>属性，指向一个方法，当该对象被<code>String.prototype.replace</code>方法调用时，会返回该方法的返回值。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token class-name">String</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span>searchValue<span class="token punctuation">,</span> replaceValue<span class="token punctuation">)</span>
<span class="token comment">// 等同于</span>
searchValue<span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>replace<span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> replaceValue<span class="token punctuation">)</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>下面是一个例子。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">const</span> x <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
x<span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>replace<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token operator">...</span>s</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token string">'Hello'</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span>x<span class="token punctuation">,</span> <span class="token string">'World'</span><span class="token punctuation">)</span> <span class="token comment">// [&quot;Hello&quot;, &quot;World&quot;]</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><p><code>Symbol.replace</code>方法会收到两个参数，第一个参数是<code>replace</code>方法正在作用的对象，上面例子是<code>Hello</code>，第二个参数是替换后的值，上面例子是<code>World</code>。</p> <h3 id="symbol-search"><a href="#symbol-search" class="header-anchor">#</a> Symbol.search</h3> <p>对象的<code>Symbol.search</code>属性，指向一个方法，当该对象被<code>String.prototype.search</code>方法调用时，会返回该方法的返回值。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token class-name">String</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function">search</span><span class="token punctuation">(</span>regexp<span class="token punctuation">)</span>
<span class="token comment">// 等同于</span>
regexp<span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>search<span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span>

<span class="token keyword">class</span> <span class="token class-name">MySearch</span> <span class="token punctuation">{</span>
  <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>value <span class="token operator">=</span> value<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>search<span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token parameter">string</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> string<span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token string">'foobar'</span><span class="token punctuation">.</span><span class="token function">search</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">MySearch</span><span class="token punctuation">(</span><span class="token string">'foo'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// 0</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br></div></div><h3 id="symbol-split"><a href="#symbol-split" class="header-anchor">#</a> Symbol.split</h3> <p>对象的<code>Symbol.split</code>属性，指向一个方法，当该对象被<code>String.prototype.split</code>方法调用时，会返回该方法的返回值。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token class-name">String</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span>separator<span class="token punctuation">,</span> limit<span class="token punctuation">)</span>
<span class="token comment">// 等同于</span>
separator<span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>split<span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> limit<span class="token punctuation">)</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>下面是一个例子。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">class</span> <span class="token class-name">MySplitter</span> <span class="token punctuation">{</span>
  <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>value <span class="token operator">=</span> value<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>split<span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token parameter">string</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> index <span class="token operator">=</span> string<span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>index <span class="token operator">===</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> string<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> <span class="token punctuation">[</span>
      string<span class="token punctuation">.</span><span class="token function">substr</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> index<span class="token punctuation">)</span><span class="token punctuation">,</span>
      string<span class="token punctuation">.</span><span class="token function">substr</span><span class="token punctuation">(</span>index <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>value<span class="token punctuation">.</span>length<span class="token punctuation">)</span>
    <span class="token punctuation">]</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token string">'foobar'</span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">MySplitter</span><span class="token punctuation">(</span><span class="token string">'foo'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token comment">// ['', 'bar']</span>

<span class="token string">'foobar'</span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">MySplitter</span><span class="token punctuation">(</span><span class="token string">'bar'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token comment">// ['foo', '']</span>

<span class="token string">'foobar'</span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">MySplitter</span><span class="token punctuation">(</span><span class="token string">'baz'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token comment">// 'foobar'</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br></div></div><p>上面方法使用<code>Symbol.split</code>方法，重新定义了字符串对象的<code>split</code>方法的行为，</p> <h3 id="symbol-iterator"><a href="#symbol-iterator" class="header-anchor">#</a> Symbol.iterator</h3> <p>对象的<code>Symbol.iterator</code>属性，指向该对象的默认遍历器方法。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">const</span> myIterable <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
myIterable<span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>iterator<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token operator">*</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">yield</span> <span class="token number">1</span><span class="token punctuation">;</span>
  <span class="token keyword">yield</span> <span class="token number">2</span><span class="token punctuation">;</span>
  <span class="token keyword">yield</span> <span class="token number">3</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token punctuation">[</span><span class="token operator">...</span>myIterable<span class="token punctuation">]</span> <span class="token comment">// [1, 2, 3]</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><p>对象进行<code>for...of</code>循环时，会调用<code>Symbol.iterator</code>方法，返回该对象的默认遍历器，详细介绍参见《Iterator 和 for...of 循环》一章。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">class</span> <span class="token class-name">Collection</span> <span class="token punctuation">{</span>
  <span class="token operator">*</span><span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>iterator<span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token keyword">while</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">!==</span> <span class="token keyword">undefined</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">yield</span> <span class="token keyword">this</span><span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
      <span class="token operator">++</span>i<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">let</span> myCollection <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Collection</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
myCollection<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
myCollection<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">;</span>

<span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">let</span> value <span class="token keyword">of</span> myCollection<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// 1</span>
<span class="token comment">// 2</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br></div></div><h3 id="symbol-toprimitive"><a href="#symbol-toprimitive" class="header-anchor">#</a> Symbol.toPrimitive</h3> <p>对象的<code>Symbol.toPrimitive</code>属性，指向一个方法。该对象被转为原始类型的值时，会调用这个方法，返回该对象对应的原始类型值。</p> <p><code>Symbol.toPrimitive</code>被调用时，会接受一个字符串参数，表示当前运算的模式，一共有三种模式。</p> <ul><li>Number：该场合需要转成数值</li> <li>String：该场合需要转成字符串</li> <li>Default：该场合可以转成数值，也可以转成字符串</li></ul> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">let</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>toPrimitive<span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token parameter">hint</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">switch</span> <span class="token punctuation">(</span>hint<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">case</span> <span class="token string">'number'</span><span class="token operator">:</span>
        <span class="token keyword">return</span> <span class="token number">123</span><span class="token punctuation">;</span>
      <span class="token keyword">case</span> <span class="token string">'string'</span><span class="token operator">:</span>
        <span class="token keyword">return</span> <span class="token string">'str'</span><span class="token punctuation">;</span>
      <span class="token keyword">case</span> <span class="token string">'default'</span><span class="token operator">:</span>
        <span class="token keyword">return</span> <span class="token string">'default'</span><span class="token punctuation">;</span>
      <span class="token keyword">default</span><span class="token operator">:</span>
        <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
     <span class="token punctuation">}</span>
   <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token number">2</span> <span class="token operator">*</span> obj <span class="token comment">// 246</span>
<span class="token number">3</span> <span class="token operator">+</span> obj <span class="token comment">// '3default'</span>
obj <span class="token operator">==</span> <span class="token string">'default'</span> <span class="token comment">// true</span>
<span class="token function">String</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span> <span class="token comment">// 'str'</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br></div></div><h3 id="symbol-tostringtag"><a href="#symbol-tostringtag" class="header-anchor">#</a> Symbol.toStringTag</h3> <p>对象的<code>Symbol.toStringTag</code>属性，指向一个方法。在该对象上面调用<code>Object.prototype.toString</code>方法时，如果这个属性存在，它的返回值会出现在<code>toString</code>方法返回的字符串之中，表示对象的类型。也就是说，这个属性可以用来定制<code>[object Object]</code>或<code>[object Array]</code>中<code>object</code>后面的那个字符串。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token comment">// 例一</span>
<span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>toStringTag<span class="token punctuation">]</span><span class="token operator">:</span> <span class="token string">'Foo'</span><span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token comment">// &quot;[object Foo]&quot;</span>

<span class="token comment">// 例二</span>
<span class="token keyword">class</span> <span class="token class-name">Collection</span> <span class="token punctuation">{</span>
  <span class="token keyword">get</span> <span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>toStringTag<span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token string">'xxx'</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">let</span> x <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Collection</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Object</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span> <span class="token comment">// &quot;[object xxx]&quot;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><p>ES6 新增内置对象的<code>Symbol.toStringTag</code>属性值如下。</p> <ul><li><code>JSON[Symbol.toStringTag]</code>：'JSON'</li> <li><code>Math[Symbol.toStringTag]</code>：'Math'</li> <li>Module 对象<code>M[Symbol.toStringTag]</code>：'Module'</li> <li><code>ArrayBuffer.prototype[Symbol.toStringTag]</code>：'ArrayBuffer'</li> <li><code>DataView.prototype[Symbol.toStringTag]</code>：'DataView'</li> <li><code>Map.prototype[Symbol.toStringTag]</code>：'Map'</li> <li><code>Promise.prototype[Symbol.toStringTag]</code>：'Promise'</li> <li><code>Set.prototype[Symbol.toStringTag]</code>：'Set'</li> <li><code>%TypedArray%.prototype[Symbol.toStringTag]</code>：'Uint8Array'等</li> <li><code>WeakMap.prototype[Symbol.toStringTag]</code>：'WeakMap'</li> <li><code>WeakSet.prototype[Symbol.toStringTag]</code>：'WeakSet'</li> <li><code>%MapIteratorPrototype%[Symbol.toStringTag]</code>：'Map Iterator'</li> <li><code>%SetIteratorPrototype%[Symbol.toStringTag]</code>：'Set Iterator'</li> <li><code>%StringIteratorPrototype%[Symbol.toStringTag]</code>：'String Iterator'</li> <li><code>Symbol.prototype[Symbol.toStringTag]</code>：'Symbol'</li> <li><code>Generator.prototype[Symbol.toStringTag]</code>：'Generator'</li> <li><code>GeneratorFunction.prototype[Symbol.toStringTag]</code>：'GeneratorFunction'</li></ul> <h3 id="symbol-unscopables"><a href="#symbol-unscopables" class="header-anchor">#</a> Symbol.unscopables</h3> <p>对象的<code>Symbol.unscopables</code>属性，指向一个对象。该对象指定了使用<code>with</code>关键字时，哪些属性会被<code>with</code>环境排除。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token class-name">Array</span><span class="token punctuation">.</span>prototype<span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>unscopables<span class="token punctuation">]</span>
<span class="token comment">// {</span>
<span class="token comment">//   copyWithin: true,</span>
<span class="token comment">//   entries: true,</span>
<span class="token comment">//   fill: true,</span>
<span class="token comment">//   find: true,</span>
<span class="token comment">//   findIndex: true,</span>
<span class="token comment">//   includes: true,</span>
<span class="token comment">//   keys: true</span>
<span class="token comment">// }</span>

Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span><span class="token class-name">Array</span><span class="token punctuation">.</span>prototype<span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>unscopables<span class="token punctuation">]</span><span class="token punctuation">)</span>
<span class="token comment">// ['copyWithin', 'entries', 'fill', 'find', 'findIndex', 'includes', 'keys']</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br></div></div><p>上面代码说明，数组有 7 个属性，会被<code>with</code>命令排除。</p> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token comment">// 没有 unscopables 时</span>
<span class="token keyword">class</span> <span class="token class-name">MyClass</span> <span class="token punctuation">{</span>
  <span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">var</span> <span class="token function-variable function">foo</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token number">2</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">with</span> <span class="token punctuation">(</span><span class="token class-name">MyClass</span><span class="token punctuation">.</span>prototype<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 1</span>
<span class="token punctuation">}</span>

<span class="token comment">// 有 unscopables 时</span>
<span class="token keyword">class</span> <span class="token class-name">MyClass</span> <span class="token punctuation">{</span>
  <span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
  <span class="token keyword">get</span> <span class="token punctuation">[</span>Symbol<span class="token punctuation">.</span>unscopables<span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">{</span> foo<span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">var</span> <span class="token function-variable function">foo</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token number">2</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">with</span> <span class="token punctuation">(</span><span class="token class-name">MyClass</span><span class="token punctuation">.</span>prototype<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 2</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br></div></div><p>上面代码通过指定<code>Symbol.unscopables</code>属性，使得<code>with</code>语法块不会在当前作用域寻找<code>foo</code>属性，即<code>foo</code>将指向外层作用域的变量。</p></div></div> <div class="page-slot page-slot-bottom"><!-- 横向自适应 -->
      <ins class="adsbygoogle"
          style="display:block"
          data-ad-client="ca-pub-7828333725993554"
          data-ad-slot="6620245489"
          data-ad-format="auto"
          data-full-width-responsive="true"></ins>
      <script>
          (adsbygoogle = window.adsbygoogle || []).push({});
      </script></div> <div class="page-edit"><!----> <div class="tags"><a href="/tags/?tag=ES6" title="标签">#ES6</a></div> <!----></div> <div class="page-nav-wapper"><div class="page-nav-centre-wrap"><a href="/pages/e85e68947502cf90/" class="page-nav-centre page-nav-centre-prev"><div class="tooltip">对象的新增方法</div></a> <a href="/pages/0c21dae358fca16b/" class="page-nav-centre page-nav-centre-next"><div class="tooltip">Set 和 Map 数据结构</div></a></div> <div class="page-nav"><p class="inner"><span class="prev">
        ←
        <a href="/pages/e85e68947502cf90/" class="prev">对象的新增方法</a></span> <span class="next"><a href="/pages/0c21dae358fca16b/">Set 和 Map 数据结构</a>→
      </span></p></div></div></div> <div class="article-list"><div class="article-title"><a href="/archives/" class="iconfont icon-bi">最近更新</a></div> <div class="article-wrapper"><dl><dd>01</dd> <dt><a href="/pages/dcedab/"><div>Nginx配置https转http</div></a> <span>12-10</span></dt></dl><dl><dd>02</dd> <dt><a href="/pages/82baa3/"><div>使用State Hook</div></a> <span>04-06</span></dt></dl><dl><dd>03</dd> <dt><a href="/pages/72710d/"><div>使用Effect Hook</div></a> <span>04-06</span></dt></dl> <dl><dd></dd> <dt><a href="/archives/" class="more">更多文章&gt;</a></dt></dl></div></div></main></div> <div class="footer"><!----> 
  Theme by
  <a href="https://github.com/xugaoyi/vuepress-theme-vdoing" target="_blank" title="本站主题">Vdoing</a> 
    | Copyright © 2021-2022
    <span><div style="width:300px;margin:0 auto; padding:20px 0;"><a target="_blank" href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=13019902000398" style="display:inline-block;text-decoration:none;height:20px;line-height:20px;"><img src="" style="float:left;"/><p style="float:left;height:20px;line-height:20px;margin: 0px 0px 0px 5px; color:#939393;">冀公网安备 13019902000398号</p></a></div></span></div> <div class="buttons"><div title="返回顶部" class="button blur go-to-top iconfont icon-fanhuidingbu" style="display:none;"></div> <div title="去评论" class="button blur go-to-comment iconfont icon-pinglun" style="display:none;"></div> <div title="主题模式" class="button blur theme-mode-but iconfont icon-zhuti"><ul class="select-box" style="display:none;"><li class="iconfont icon-zidong">
          跟随系统
        </li><li class="iconfont icon-rijianmoshi">
          浅色模式
        </li><li class="iconfont icon-yejianmoshi">
          深色模式
        </li><li class="iconfont icon-yuedu">
          阅读模式
        </li></ul></div></div> <div class="body-bg" style="background:url() center center / cover no-repeat;opacity:0.5;"></div> <!----> <div class="custom-html-window custom-html-window-rb" style="display:;"><div class="custom-wrapper"><i class="close-but">×</i> <div><!-- 固定160*160px -->
      <ins class="adsbygoogle"
          style="display:inline-block;max-width:160px;max-height:160px"
          data-ad-client="ca-pub-7828333725993554"
          data-ad-slot="8377369658"></ins>
      <script>
          (adsbygoogle = window.adsbygoogle || []).push({});
      </script>
      </div></div></div></div><div class="global-ui"></div></div>
    <script src="/assets/js/app.ae5bf724.js" defer></script><script src="/assets/js/2.72b09a26.js" defer></script><script src="/assets/js/3.96877024.js" defer></script><script src="/assets/js/95.8042bfa3.js" defer></script>
  </body>
</html>